package com.szalay.desktopsearch.indexer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 * Indexer task.
 * @author szalay
 */
public class IndexingTask implements StatefulJob {
    /** Logger. */
    private final static Logger logger = LoggerFactory.getLogger(IndexingTask.class);
    
    /** Solr. */
    private SolrServer solr;
    
    /** Tika mime types. */
    private final Tika tika = new Tika();
    
    @Override
    public void execute(final JobExecutionContext jec) throws JobExecutionException {
        solr = (SolrServer) jec.getJobDetail().getJobDataMap().get(SolrServer.class.getName());
        
        //Start scanning at the user home
        final File userHome = new File(System.getProperty("user.home"));
        scanFiles(userHome);
        
        //Commit
        try {
            solr.optimize();
            solr.commit();
        } catch(Exception ex) {
            logger.warn(null, ex);
        } 
    }
    
    private void scanFiles(final File root) {
        final File[] children = root.listFiles();
        for (final File file : children) {
            if (file.isDirectory()) {
                scanFiles(file);
            }
            else {
                try {
                    indexFile(file);
                }
                catch (Exception ex) {
                    logger.warn(null, ex);
                }
            }
        }
    }
    
    private void indexFile(final File file) throws SolrServerException, IOException, TikaException, SAXException {
        //Check if document exists...
        final SolrQuery getByIdQuery = new SolrQuery();
        getByIdQuery.addField(Fields.PATH);
        getByIdQuery.addField(Fields.LAST_MODIFIED_DATE);
        getByIdQuery.addFilterQuery(Fields.PATH + file.getAbsolutePath());
        getByIdQuery.setQuery("*:*");
        
        final QueryResponse idQueryResponse = solr.query(getByIdQuery);
        if (idQueryResponse.getResults().getNumFound() > 0) {
            final SolrDocument foundDoc = idQueryResponse.getResults().get(0);
            @SuppressWarnings("unchecked")
            final List<Date> dates = (List<Date>) foundDoc.getFieldValue(Fields.LAST_MODIFIED_DATE);
            if (!dates.isEmpty()) {
                final Date mdDate = dates.get(0);
                if ((mdDate != null) && (file.lastModified() < mdDate.getTime())) {
                    //File dosn't have to be indexed
                    return;
                }
            }
        }
        
        //Index a new document
        final SolrInputDocument document = new SolrInputDocument();
        document.setField(Fields.PATH, file.getAbsolutePath());
        
        //set mime type
        final FileInputStream fileInput = new FileInputStream(file);
        final String mimeType = tika.detect(fileInput, file.getName());
        document.setField(Fields.MIMETYPE, mimeType);
        
        //set time modified
        final Date lastModified = new Date(file.lastModified());
        document.setField(Fields.LAST_MODIFIED_DATE, lastModified);
        
        //Size
        document.setField(Fields.SIZE, Long.valueOf(file.length()).toString());
        
        //set content
        final String contentString = tika.parseToString(file);
        document.setField(Fields.CONTENT, contentString);
        
        //Other metadata
        final Parser parser = new AutoDetectParser();
        final Metadata metadata = new Metadata();
        final ParseContext context = new ParseContext();
        final ContentHandler textHandler = new BodyContentHandler();
        final FileInputStream fileInput2 = new FileInputStream(file);
        parser.parse(fileInput2, textHandler, metadata, context);
        fileInput2.close();
        for (final String name : metadata.names()) {
            if (name.equals(Metadata.TITLE)) {
                final String[] titles = metadata.getValues(name);
                if ((titles != null) && (titles.length > 0)) {
                    document.setField(Fields.TITLE, titles[0]);
                }
            }
        }

        //remove and add to solr
        solr.deleteById(file.getAbsolutePath());
        solr.add(document);
    }  
}
